package com.webster.isw.core.service.impl;

import com.webster.isw.core.config.Constants;
import com.webster.isw.core.exception.ExceptionUtil;
import com.webster.isw.core.exception.SystemException;
import com.webster.isw.core.gen.entity.ScTriggerLog;
import com.webster.isw.core.gen.mapper.ScTriggerLogMapper;
import com.webster.isw.core.service.TriggerService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 触发器
 * Created by Webster on 16/5/8.
 */
@Service("triggerService")
public class TriggerServiceImpl extends BaseServiceImpl implements TriggerService {
    /**
     * <p>
     * Field logSchFlag: 常量
     * </p>
     */

    private String logSchFlag = "LOG_SCH_FLAG";

    /**
     * Field detaledRecords: 常量
     * </p>
     */
    private String detaledRecords = "DETAILED_RECORDS";

    /**
     * <p>
     * Field scTriggerLogMapper: 触发器监听mapper
     * </p>
     */
    @Autowired
    private ScTriggerLogMapper scTriggerLogMapper;

    /**
     * Description: 保存未正常触发的记录
     */
    @Override
    public void saveErrorTrigger(Trigger trigger) {
        ScTriggerLog scTriggerLog = new ScTriggerLog();
        scTriggerLog.setId(UUID.randomUUID().toString());
        scTriggerLog.setStatusStr("misfired");
        scTriggerLog.setTriggerName(trigger.getKey().getName());
        scTriggerLog.setTriggerGroup(trigger.getKey().getGroup());
        scTriggerLog.setJobName(trigger.getJobKey().getName());
        scTriggerLog.setJobGroup(trigger.getJobKey().getGroup());
        scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
        scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
        scTriggerLog.setThreadName(Thread.currentThread().getName());
        scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
        scTriggerLog.setCreateAt(new Date());
        scTriggerLogMapper.insertSelective(scTriggerLog);

    }

    /**
     * Description: 准备触发
     */
    @Override
    public void saveFiredTrigger(JobExecutionContext context) throws SystemException {
        try {

            // 是否记录执行历史(true记录,false不记录)
            String log = getParamService().getSysParamPreFerDefault(logSchFlag);
            boolean logRecords = null == log ? false : Boolean.valueOf(log);
            if (!logRecords) {
                return;
            }

            // 是否详细记录执行历史(true记录,false不记录)
            String dr = getParamService().getSysParamPreFerDefault(this.detaledRecords);
            boolean detailedRecords = null == dr ? false : Boolean.valueOf(dr);
            if (!detailedRecords) {
                return;
            }

            // 获得计划任务实例
            Scheduler s = context.getScheduler();

            // 删除当前ID已经有的记录
            this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

            // 写入新的记录
            ScTriggerLog scTriggerLog = new ScTriggerLog();
            scTriggerLog.setId(context.getFireInstanceId());
            scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
            scTriggerLog.setRealFireAt(context.getFireTime());
            scTriggerLog.setStatusStr("triggering");
            scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
            scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
            scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
            scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
            scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
            scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
            scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
            scTriggerLog.setThreadName(Thread.currentThread().getName());
            scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
            scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
            scTriggerLog.setScheduledName(s.getSchedulerName());
            scTriggerLog.setCreateAt(new Date());
            this.scTriggerLogMapper.insertSelective(scTriggerLog);
        } catch (SchedulerException e) {
            throw new SystemException(e);
        }
    }

    /**
     * Description: 判断是否否决
     *
     * @param context
     */
    @Override
    public boolean isJobVetoed(JobExecutionContext context) throws SystemException {
        try {

            // 是否否决
            boolean vetoed = false;

            // 是否记录执行历史(true记录,false不记录)
            String log = getParamService().getSysParamPreFerDefault(this.logSchFlag);
            boolean logRecords = null == log ? false : Boolean.valueOf(log);
            if (!logRecords) {
                return vetoed;
            }

            // 是否详细记录执行历史(true记录,false不记录)
            String dr = getParamService().getSysParamPreFerDefault(this.detaledRecords);
            boolean detailedRecords = null == dr ? false : Boolean.valueOf(dr);
            if (!detailedRecords) {
                return vetoed;
            }

            // 获得计划任务实例
            Scheduler s = context.getScheduler();

            // 删除当前ID已经有的记录
            this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

            // 写入新的记录
            ScTriggerLog scTriggerLog = new ScTriggerLog();
            scTriggerLog.setId(context.getFireInstanceId());
            scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
            scTriggerLog.setRealFireAt(context.getFireTime());
            scTriggerLog.setStatusStr("vetoed(" + vetoed + ")");
            scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
            scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
            scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
            scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
            scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
            scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
            scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
            scTriggerLog.setThreadName(Thread.currentThread().getName());
            scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
            scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
            scTriggerLog.setScheduledName(s.getSchedulerName());
            scTriggerLog.setCreateAt(new Date());
            this.scTriggerLogMapper.insertSelective(scTriggerLog);
            return vetoed;
        } catch (SchedulerException e) {
            throw new SystemException(e);
        }
    }

    /**
     * Description: 准备执行作业
     *
     * @param context
     */
    @Override
    public void saveIntentStartJob(JobExecutionContext context) throws SystemException {
        try {

            // 是否记录执行历史(true记录,false不记录)
            String log = getParamService().getSysParamPreFerDefault(this.logSchFlag);
            boolean logRecords = null == log ? false : Boolean.valueOf(log);
            if (!logRecords) {
                return;
            }

            // 是否详细记录执行历史(true记录,false不记录)
            String dr = getParamService().getSysParamPreFerDefault(this.detaledRecords);
            boolean detailedRecords = null == dr ? false : Boolean.valueOf(dr);
            if (!detailedRecords) {
                return;
            }

            // 获得计划任务实例
            Scheduler s = context.getScheduler();

            // 删除当前ID已经有的记录
            this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

            // 写入新的记录
            ScTriggerLog scTriggerLog = new ScTriggerLog();
            scTriggerLog.setId(context.getFireInstanceId());
            scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
            scTriggerLog.setRealFireAt(context.getFireTime());
            scTriggerLog.setStatusStr("toBeExecuted");
            scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
            scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
            scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
            scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
            scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
            scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
            scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
            scTriggerLog.setThreadName(Thread.currentThread().getName());
            scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
            scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
            scTriggerLog.setScheduledName(s.getSchedulerName());
            scTriggerLog.setCreateAt(new Date());
            this.scTriggerLogMapper.insertSelective(scTriggerLog);
        } catch (SchedulerException e) {
            throw new SystemException(e);
        }
    }

    /**
     * Description: 作业执行被否决
     *
     * @param context
     */
    @Override
    public void saveVetoedJob(JobExecutionContext context) throws SystemException {
        try {

            // 获得计划任务实例
            Scheduler s = context.getScheduler();

            // 删除当前ID已经有的记录
            this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

            // 写入新的记录
            ScTriggerLog scTriggerLog = new ScTriggerLog();
            scTriggerLog.setId(context.getFireInstanceId());
            scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
            scTriggerLog.setRealFireAt(context.getFireTime());
            scTriggerLog.setStatusStr("executionVetoed");
            scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
            scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
            scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
            scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
            scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
            scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
            scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
            scTriggerLog.setThreadName(Thread.currentThread().getName());
            scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
            scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
            scTriggerLog.setScheduledName(s.getSchedulerName());
            scTriggerLog.setCreateAt(new Date());
            this.scTriggerLogMapper.insertSelective(scTriggerLog);
        } catch (SchedulerException e) {
            throw new SystemException(e);
        }
    }

    /**
     * Description: 作业执行完毕
     *
     * @param context
     * @param jobException
     */
    @Override
    public void saveCompletedJob(JobExecutionContext context, JobExecutionException jobException) throws SchedulerException {

        // 异常信息
        String exceptionDetail = null;

        // 如果作业异常,则放入信息到result中
        if (null != jobException) {
            Map<String, Object> result = new HashMap<String, Object>();
            result.put("status", "error");
            result.put("jobException", jobException);
            context.setResult(result);
            // 获得异常信息
            String expMessage = ExceptionUtil.createStackTrackMessage(jobException);
            exceptionDetail = expMessage; // 异常详细信息
            if (exceptionDetail.length() > Constants.EXCEPTION_MSG_LENGTH) {
                exceptionDetail = exceptionDetail.substring(0, Constants.EXCEPTION_MSG_LENGTH);
            }
        }

        // 是否记录执行历史(true记录,false不记录)
        String log = getParamService().getSysParamPreFerDefault(this.logSchFlag);
        boolean logRecords = null == log ? false : Boolean.valueOf(log);
        if (!logRecords) {
            return;
        }

        // 是否详细记录执行历史(true记录,false不记录)
        String dr = getParamService().getSysParamPreFerDefault(this.detaledRecords);
        boolean detailedRecords = null == dr ? false : Boolean.valueOf(dr);
        if (!detailedRecords) {
            return;
        }

        // 获得计划任务实例
        Scheduler s = context.getScheduler();

        // 删除当前ID已经有的记录
        this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

        // 写入新的记录
        ScTriggerLog scTriggerLog = new ScTriggerLog();
        scTriggerLog.setId(context.getFireInstanceId());
        scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
        scTriggerLog.setRealFireAt(context.getFireTime());
        scTriggerLog.setRealEndAt(new Date());
        scTriggerLog.setJobCostTime((int) context.getJobRunTime());
        scTriggerLog.setStatusStr("executed");
        scTriggerLog.setErrorMsg(exceptionDetail);
        scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
        scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
        scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
        scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
        scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
        scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
        scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
        scTriggerLog.setThreadName(Thread.currentThread().getName());
        scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
        scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
        scTriggerLog.setScheduledName(s.getSchedulerName());
        scTriggerLog.setCreateAt(new Date());
        this.scTriggerLogMapper.insertSelective(scTriggerLog);
    }

    /**
     * Description: 触发完成
     *
     * @param context
     * @param triggerInstructionCode
     */
    @Override
    @SuppressWarnings("unchecked")
    public void saveCompletedTrigger(JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) throws SystemException {
        try {

            // 状态和异常信息
            String status = "complete";
            String exceptionDetail = null;

            // 获得result
            Object o = context.getResult();
            if (null != o && o instanceof Map) {
                Map<String, Object> result = (Map<String, Object>) o;
                status = result.get("status").toString();
                JobExecutionException jobException = (JobExecutionException) result.get("jobException");

                // 获得异常信息
                exceptionDetail = ExceptionUtil.createStackTrackMessage(jobException);
                if (exceptionDetail.length() > Constants.EXCEPTION_MSG_LENGTH) {
                    exceptionDetail = exceptionDetail.substring(0, Constants.EXCEPTION_MSG_LENGTH);
                }
            }

            // 是否记录执行历史(true记录,false不记录)
            String log = getParamService().getSysParamPreFerDefault(this.logSchFlag);
            boolean logRecords = null == log ? false : Boolean.valueOf(log);
            if (!logRecords) {
                return;
            }

            // 获得计划任务实例
            Scheduler s = context.getScheduler();

            // 删除当前ID已经有的记录
            this.scTriggerLogMapper.deleteByPrimaryKey(context.getFireInstanceId());

            // 写入新的记录
            ScTriggerLog scTriggerLog = new ScTriggerLog();
            scTriggerLog.setId(context.getFireInstanceId());
            scTriggerLog.setIntendFireAt(context.getScheduledFireTime());
            scTriggerLog.setRealFireAt(context.getFireTime());
            scTriggerLog.setRealEndAt(new Date());
            scTriggerLog.setJobCostTime((int) context.getJobRunTime());
            scTriggerLog.setStatusStr(status);
            scTriggerLog.setResult(triggerInstructionCode.toString());
            scTriggerLog.setErrorMsg(exceptionDetail);
            scTriggerLog.setTriggerName(context.getTrigger().getKey().getName());
            scTriggerLog.setTriggerGroup(context.getTrigger().getKey().getGroup());
            scTriggerLog.setJobName(context.getJobDetail().getKey().getName());
            scTriggerLog.setJobGroup(context.getJobDetail().getKey().getGroup());
            scTriggerLog.setJobClass(context.getJobDetail().getJobClass().getName());
            scTriggerLog.setThreadGroupName(Thread.currentThread().getThreadGroup().getName());
            scTriggerLog.setThreadId(Long.toString(Thread.currentThread().getId()));
            scTriggerLog.setThreadName(Thread.currentThread().getName());
            scTriggerLog.setThreadPriority(Long.toString(Thread.currentThread().getPriority()));
            scTriggerLog.setScheduledId(s.getSchedulerInstanceId());
            scTriggerLog.setScheduledName(s.getSchedulerName());
            scTriggerLog.setCreateAt(new Date());
            this.scTriggerLogMapper.insertSelective(scTriggerLog);
        } catch (SchedulerException e) {
            throw new SystemException(e);
        }
    }

}
